package uk.ac.sanger.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
import java.util.Set;

import org.biojava.dasobert.das.DasSpec;
import org.biojava.dasobert.das2.io.DasSourceReaderImpl;
import org.biojava.dasobert.dasregistry.Das1Source;
import org.biojava.dasobert.dasregistry.DasCoordinateSystem;
import org.biojava.dasobert.dasregistry.DasSource;
import org.biojava.services.das.dao.DasSourceManager;
import org.biojava.services.das.registry.DasRegistrySql;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * class to read proserver.ini file and create DasSources
 * 
 * @author jw12
 * 
 */
public class ProserverIniReader {

	List<DasSource> sources = null;
	List<DasCoordinateSystem> knownCoords = null;
	Set<String> privateSources = null;

	public static void main(String args[]) {
		ProserverIniReader reader = new ProserverIniReader();
		reader.createSources("http:////localhost:8080/das/sources");

	}

	/**
	 * 
	 * @param path
	 *            to proserver.ini file
	 */
	public List<DasSource> createSources(String dazzleUrl) {

		InputStream inStream = this.getClass().getResourceAsStream(
				"/proserver.ini");// included in resources as file permissions
									// mean we can't get it from nfs
		// change this when new vms set up and the sources command should work
		// for proserver

		BufferedReader proserverFile = new BufferedReader(
				new InputStreamReader(inStream));
		// File file = new File(path);// read in sources from proserver
		sources = new ArrayList<DasSource>();

		// read in public ids that are allowed in the sources response

		// can we get the allowed sources from the dsn?
		ReadPrivateSources publicSources = new ReadPrivateSources();
		Set<String> privateIds = publicSources.readPrivateIds();

		// get sources from sanger dazzle instance and add to sources list if
		// contained in list of public sanger sources
		DasSource[] dazzlesources = readSourcesFromDazzle(dazzleUrl);

		for (DasSource dazzleSource : dazzlesources) {
			if (!privateIds.contains(dazzleSource.getId())) {
				dazzleSource.setSpecification(DasSpec.SPEC1_6E.toString());
				sources.add(dazzleSource);

			}

		}
		System.out.println("initialinising sql from spring");
		BeanFactory ctx=(new ClassPathXmlApplicationContext("SpringDAO.xml"));
		DasRegistrySql sql=(DasRegistrySql)ctx.getBean("registryBean");

		try {
			knownCoords = sql.getAllCoordinateSystems();
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		DasCoordinateSystemGuesser guesser=new DasCoordinateSystemGuesser(knownCoords);
		Scanner scanner = new Scanner(proserverFile);
		scanner.useDelimiter("\\n\\[");// matches beginning of new source
		// without first bracket
		int i = 0;
		List<DasSource> withoutCoords=new ArrayList<DasSource>();;
		
		while (scanner.hasNext()) {

			String sourceInfo = scanner.next();
			// System.out.print("\n" + sourceInfo +
			// "\n\n");
			DasSource source = createSourceFromInfo(sourceInfo);
			if (!source.getId().equals("general") && i != 0) {
				DasCoordinateSystem[] coords = source.getCoordinateSystem();
				//if no coords guess one
				source=guesser.addGuesedCoordinate(source, coords);
				if (!privateIds.contains(source.getId())) {// only add the
					// source from proserver if
					// its
					// configured
					// public in
					// das_conf.ini

					sources.add(source);
				}
				if (source.getId().equals("decipher")) {
					System.out.println("decipher added to sources");
					sources.add(source);
				}
				if(source.getCoordinateSystem().length==0){
					withoutCoords.add(source);
					
				}
			}

			i++;
			// if(i>10)break;
		}
		System.out
				.println("number of sources without coords = "
						+ withoutCoords.size());
		System.out.println("dazzle sources size=" + dazzlesources.length);
		System.out.println("sources size=" + sources.size());
		for(DasSource sourceWithNoCoord:withoutCoords){
			System.out.println(sourceWithNoCoord.getId()+":"+sourceWithNoCoord.getDescription()+sourceWithNoCoord.getAdminemail());
		}

		return sources;
	}


	private DasSource[] readSourcesFromDazzle(String dazzleUrl) {
		DasSourceReaderImpl reader = new DasSourceReaderImpl();
		URL url = null;
		System.out.println("reading dazzle from " + dazzleUrl);
		try {
			url = new URL(dazzleUrl);
		} catch (MalformedURLException e2) {
			// TODO Auto-generated catch block
			e2.printStackTrace();
		}

		DasSource[] dazzlesources = reader.readDasSource(url);
		return dazzlesources;
	}

	private DasSource createSourceFromInfo(String sourceInfo) {
		// strip out id from before first ]
		String lines[] = sourceInfo.split("\\n");
		DasSource source = new Das1Source();
		for (String line : lines) {
			if (line.startsWith("#")) {
				// ignore comments
			} else if (line.contains("=")) {
				String keyNValue[] = line.split("=", 2);
				if (keyNValue.length > 1) {
					String key = keyNValue[0].trim();
					String value = keyNValue[1].trim();
					// System.out.println("key="+key+" value="+value);
					// System.out.println(key + "=" + value);
					if (key.equals("maintainer")) {
						source.setAdminemail(value);
					}
					if (key.equals("description")) {

						String noHtml = value.replaceAll("\\<.*?>", "");
						source.setDescription(noHtml);
					}
					if (key.equals("dsncreated")) {
						// source.setRegisterDate(d)
					}
					if (key.equals("coordinates")) {
						// System.out.println(value);
						String coordsString = null;
						String testCode = null;

						String arrowSep[] = value.split(">");
						// System.out.println(arrowSep.length);
						if (arrowSep.length > 1) {
							coordsString = arrowSep[0].replace("=", "")
									.replace("-", "");// some arrows seem to be
							// like this => and some
							// are like this ->
							testCode = arrowSep[1];
							// System.out.println("testCode="+testCode);

						} else {
							coordsString = value;
						}
						DasCoordinateSystem coord = DasCoordinateSystem
								.fromStringSepVersion(coordsString);
						if (testCode == null
								&& coord.getCategory().equals("Chromosome")) {
							testCode = "1:10000000,11000000";// lets guess a
							// testcode here
							// for a
							// chromosome
							// source
							// 1million
							// bases
						}
						coord.setTestCode(testCode);
						for (DasCoordinateSystem known : knownCoords) {
							if (known.equalsUsingOrganismName(coord)) {// for
								// coords
								// with
								// no
								// organism
								// need
								// to
								// make
								// sure
								// "" or
								// null
								// means
								// the
								// same?
								// System.out.println("match found="
								// + coord.toString() + " | "
								// + known.toString());
								coord.setNCBITaxId(known.getNCBITaxId());
								coord.setUniqueId(known.getUniqueId());
							}
						}
						DasCoordinateSystem[] coords = new DasCoordinateSystem[1];
						coords[0] = coord;
						source.setCoordinateSystem(coords);
					}
					if (key.equals("capabilities")) {
						// System.out.println(value);
						if (value.contains("features")) {
									List<String>caps=new ArrayList();
									caps.add("features");
							source.setCapabilities(caps);
						}
					}
					if (key.equals("title")) {
						source.setNickname(value);
					}

				}

			} else if (line.contains("]")) {// have already chopped first
				// bracket off so only trailing
				// bracket to check for
				String id = line.replace("]", "");
				source.setId(id);
				// lets set capabilities for features for all as hardly any have
				// them?
				List<String> caps = new ArrayList();
				caps.add("sources");
				caps.add("features");
				caps.add("stylesheet");
				caps.add("types");
				source.setCapabilities(caps);
				source.setUrl("http://das.sanger.ac.uk/das/" + id);
				// System.out.println("id="+line);
			}
		}
		if(source.getNickname()=="")source.setNickname(source.getId());
		if(source.getAdminemail()=="")source.setAdminemail("das-core@sanger.ac.uk");
		return source;
	}

}
